Skip to content

fix(build): embed MediaRemoteAdapter.framework so the built app is relocatable#577

Open
hoishing wants to merge 1 commit into
altic-dev:mainfrom
hoishing:pr/embed-mediaremoteadapter
Open

fix(build): embed MediaRemoteAdapter.framework so the built app is relocatable#577
hoishing wants to merge 1 commit into
altic-dev:mainfrom
hoishing:pr/embed-mediaremoteadapter

Conversation

@hoishing

@hoishing hoishing commented Jul 11, 2026

Copy link
Copy Markdown

Description

The MediaRemoteAdapter Swift package product is linked but the app target has no Embed Frameworks build phase. As a result, xcodebuild build leaves the dynamic framework in DerivedData's PackageFrameworks/ and the app resolves it only via a dev-time rpath. The built .app runs in place but crashes as soon as it is copied elsewhere (e.g. to /Applications):

dyld: Library not loaded: @rpath/MediaRemoteAdapter.framework/Versions/A/MediaRemoteAdapter

Archive-based builds embed the framework implicitly, which is why this is not seen when distributing via Organizer — but a plain build product is not relocatable.

This PR adds an Embed Frameworks copy-files phase (Embed & Sign / CodeSignOnCopy) so MediaRemoteAdapter.framework is packaged into Contents/Frameworks/ and the build product is self-contained and relocatable.

Type of Change

  • 🐞 Bug fix
  • ✨ New feature
  • 💥 Breaking change
  • 🧹 Chore
  • 📝 Documentation update

Related Issue or Discussion

Closes #580

Testing

  • Tested on Intel Mac
  • Tested on Apple Silicon Mac
  • Tested on macOS version: 26.5.2
  • Ran linter locally: swiftlint --strict --config .swiftlint.yml Sources
  • Ran formatter locally: swiftformat --config .swiftformat Sources
  • Ran tests locally:

Verified: a clean xcodebuild -configuration Release build now produces FluidVoice.app/Contents/Frameworks/MediaRemoteAdapter.framework, codesign --verify --deep --strict passes, and the app launches with no dyld errors after being copied to /Applications (previously crashed on launch there).

Screenshots / Video

  • No UI/visual changes; screenshots/video are not applicable.

Notes

Project-file-only change: adds one PBXCopyFilesBuildPhase (dstSubfolderSpec = 10) plus its PBXBuildFile (with CodeSignOnCopy) and wires it into the app target's buildPhases. No source changes.

🤖 Generated with Claude Code

The MediaRemoteAdapter Swift package product was linked but had no Embed
Frameworks build phase, so `xcodebuild build` left the dynamic framework in
DerivedData's PackageFrameworks/ and resolved it only via a dev-time rpath.
The built .app ran in place but crashed once copied elsewhere (e.g. to
/Applications) with "Library not loaded: @rpath/MediaRemoteAdapter.framework".

Add an Embed Frameworks copy-files phase (Embed & Sign / CodeSignOnCopy) so
the framework is packaged into Contents/Frameworks and the build product is
relocatable. Archive-based builds embedded it implicitly; plain `build` did
not.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 5ebe9f64dffa8394b9151f48a3cb841d5f02e2ef)
@github-actions

Copy link
Copy Markdown

The PR Policy check is blocking this PR because required template information is missing.

Please update the PR description with:

  • Related Issue or Discussion

Screenshots or video are required for UI, UX, settings, onboarding, overlay, menu bar, or visual behavior changes. If this PR has no visual changes, check the no-visual-change box in the template.

If this remains incomplete for 48 hours after opening, the PR may be closed.

@github-actions github-actions Bot added the needs PR template Pull request is missing required template content. label Jul 11, 2026
@greptile-apps

greptile-apps Bot commented Jul 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a relocatability bug where MediaRemoteAdapter.framework was left in DerivedData's PackageFrameworks/ directory during a plain xcodebuild build, causing the app to crash with a dyld: Library not loaded error when moved outside its build location.

  • Adds a PBXCopyFilesBuildPhase with dstSubfolderSpec = 10 (Frameworks) and CodeSignOnCopy, which correctly embeds MediaRemoteAdapter.framework into FluidVoice.app/Contents/Frameworks/ at build time.
  • Wires the new phase into the app target's buildPhases list after Sources, Frameworks, and Resources — the correct ordering for Xcode.
  • Change is project-file only; no source modifications.

Confidence Score: 4/5

The fix is technically correct and tightly scoped; the only open question is whether any of the other four SPM-linked frameworks are also dynamic and need the same embed step.

The Xcode project change is mechanically sound — correct dstSubfolderSpec, correct CodeSignOnCopy attribute, correct productRef, correct build-phase ordering. The one gap is that four other SPM products (SwiftWhisper, DynamicNotchKit, AppUpdater, FluidAudio) are also linked in the Frameworks phase but not embedded; if any declare type: .dynamic, the relocatability problem would persist for those dependencies.

Fluid.xcodeproj/project.pbxproj — specifically the linkage of SwiftWhisper, DynamicNotchKit, AppUpdater, and FluidAudio, which should be verified as static before closing.

Comments Outside Diff (1)

  1. Fluid.xcodeproj/project.pbxproj, line 60-65 (link)

    P2 Other dynamic SPM products may need the same treatment

    The Frameworks phase links four other SPM products — SwiftWhisper, DynamicNotchKit, AppUpdater, and FluidAudio — in addition to MediaRemoteAdapter. If any of those packages declare type: .dynamic in their Package.swift, they will have the same dyld-rpath problem outside DerivedData that this PR is fixing for MediaRemoteAdapter. Worth confirming that each of those packages is either a static library or already embedded through another mechanism before closing this out.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: Fluid.xcodeproj/project.pbxproj
    Line: 60-65
    
    Comment:
    **Other dynamic SPM products may need the same treatment**
    
    The Frameworks phase links four other SPM products — `SwiftWhisper`, `DynamicNotchKit`, `AppUpdater`, and `FluidAudio` — in addition to `MediaRemoteAdapter`. If any of those packages declare `type: .dynamic` in their `Package.swift`, they will have the same dyld-rpath problem outside DerivedData that this PR is fixing for `MediaRemoteAdapter`. Worth confirming that each of those packages is either a static library or already embedded through another mechanism before closing this out.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Codex

Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
Fluid.xcodeproj/project.pbxproj:60-65
**Other dynamic SPM products may need the same treatment**

The Frameworks phase links four other SPM products — `SwiftWhisper`, `DynamicNotchKit`, `AppUpdater`, and `FluidAudio` — in addition to `MediaRemoteAdapter`. If any of those packages declare `type: .dynamic` in their `Package.swift`, they will have the same dyld-rpath problem outside DerivedData that this PR is fixing for `MediaRemoteAdapter`. Worth confirming that each of those packages is either a static library or already embedded through another mechanism before closing this out.

Reviews (1): Last reviewed commit: "fix(build): embed MediaRemoteAdapter.fra..." | Re-trigger Greptile

@github-actions github-actions Bot removed the needs PR template Pull request is missing required template content. label Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Release build crashes on launch after moving the .app (MediaRemoteAdapter.framework not embedded)

1 participant